<?php
require_once dirname(__file__) . "/../../models/pingpp/init.php";

use  Illuminate\Support\Facades\Event;

/**
 * 提供和PingXX统一支付相关的接口
 */
class Payment_GatewayController extends BaseController
{

	protected $layout = 'layouts.master';

	// TODO: put the API_KEY and APP_ID into the config file
	// const API_KEY = 'sk_test_XbDS8Cf9mjX11Gy5C4b9WznT';
	const API_KEY = 'sk_live_ab1Wv5T4izf5y58480mb5GWT';

	// const APP_ID_ANDROID = 'app_LqjrHSzr1a54SWXv';
	const APP_ID_ANDROID = 'app_jn1u90zn5mjDvTWX';

	const APP_ID_IOS = 'app_jn1u90zn5mjDvTWX';

	const APP_ID_WECHAT = 'app_Xjv98Ovrv5SSrXHW';

	const APP_ID_PC = 'app_mjXLiLWHSSaPPKyj';

	public function __construct()
	{
		parent::__construct();

		// TODO: generate the public & private keys
		// \Pingpp\Pingpp::setPrivateKeyPath(__DIR__ . '/your_rsa_private_key.pem');

		\Pingpp\Pingpp::setApiKey(self::API_KEY);
	}

	public function query($chId)
	{
		$charge = \Pingpp\Charge::retrieve($chId);

		if (!$charge) {
			return $this->makeView('errors.404', [
				'这个charge对象不存在',
			], 404);
		}

		return Response::json($charge)->header('Content-Type', 'application/json')->setStatusCode(200);
	}

	/**
	 * 生成统一支付的charge对象
	 */
	public function charge()
	{
		$params = Input::get();

		Validator::extend('valid_metadata', function ($attr, $value, $parameters) {
			if (!is_array($value)) {
				return false;
			}
			if (!isset($value['pay_type']) || !in_array($value['pay_type'], [
					'wallet_recharge',
					'wallet_reward',
					'order',
				])
			) {
				return false;
			}
			if ($value['pay_type'] == 'wallet_recharge') {
				if (!isset($value['user_id'])) {
					return false;
				}
			} else {
				if ($value['pay_type'] == 'wallet_reward') {
					if (!isset($value['user_id']) || !isset($value['from_user_id'])) {
						return false;
					}
				} else {
					if ($value['pay_type'] == 'order') {
						if (!isset($value['question_id'])) {
							return false;
						}
					}
				}
			}

			return true;
		});

		$rules = [
			'channel'         => [
				'required',
				'regex:/^(alipay|alipay_wap|alipay_qr|alipay_pc_direct|bfb|bfb_wap|upacp|upacp_wap|upacp_pc|cp_b2b|wx|wx_pub|wx_pub_qr|yeepay_wap|jdpay_wap|cnp_u|cnp_f|applepay_upacp)$/i',
			],
			'device'          => [
				'required',
				'regex:/^(pc|wechat|android|ios)$/i',
			],
			'amount'          => 'required',
			'subject'         => 'required',
			'body'            => 'required',
			'current_user_id' => 'required',
			'metadata'        => 'required|valid_metadata',
		];
		$messages = [
			'channel.required'         => '请提交渠道',
			'channel.regex'            => '提交的渠道类型错误',
			'device.required'          => '请提交发起请求的设备的种类',
			'channel.regex'            => '提交的设备类型错误',
			'amount.required'          => '请提交商品的总价格',
			'subject.required'         => '请提交商品的标题',
			'body.required'            => '请提交商品的描述',
			'current_user_id.required' => '请提供当前用户的id',
			'metadata.required'        => '请提交商品的元数据',
			'metadata.valid_metadata'  => '提交的元数据的格式有误',
		];

		$channel = isset($params['channel']) ? $params['channel'] : '';
		$this->addExtraRulesBasedOnChannel($channel, $rules, $messages);

		$validator = Validator::make($params, $rules, $messages);
		if ($validator->fails()) {
			// the given data did not pass validation
			Log::error(__METHOD__ . __LINE__ . json_encode($params));

			return $this->makeView('errors.400', $validator->errors(), 400);
		}

		Log::info(__METHOD__ . __LINE__ . json_encode($params,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));

		$amount 		= $params['amount'];
		$subject 		= $params['subject']; // 商品名称
		$body 			= $params['body']; // 商品的描述信息
		$device 		= $params['device'];
		$metadata 		= $params['metadata']; // 订单的元数据
		$currentUserId 	= $params['current_user_id'];
		$orderNo = $this->generateOrderNo($currentUserId);

		$extra = $this->getExtraFromChannel($channel, $params);
		$appId = $this->getAppIdByDevice($device);

		
		try {
			$ch = \Pingpp\Charge::create([
				'subject'   => $subject,
				'body'      => $body,
				 'amount'    => $amount,
				 // 'amount'    => 1,
				'order_no'  => $orderNo,
				'currency'  => 'cny',
				'extra'     => $extra,
				'channel'   => $channel,
				'client_ip' => $_SERVER['REMOTE_ADDR'],
				'app'       => [
					'id' => $appId,
				],
				'metadata'  => $metadata,
			]);


			Log::info(__METHOD__ . __LINE__ . ' ch info ' . json_encode($ch,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));
			

			return Response::json($ch)->header('Content-Type', 'application/json')->setStatusCode(200);
		} catch (\Pingpp\Error\Base $e) {
			// 捕获报错信息
			if ($e->getHttpStatus() != null) {
				return $this->makeView(sprintf("errors.%s", $e->getHttpStatus()), $e->getHttpBody(), $e->getHttpStatus());
			} else {
				$this->makeView("errors.503", $e->getHttpBody(), $e->getHttpStatus());
			}
		}
	}

	/**
	 * @param integer $currentUserId
	 */
	protected function generateOrderNo($currentUserId)
	{
		$date = date('YmdHis');
		$subfix = ($date / (1 + $currentUserId)) & 7;

		return $date . $currentUserId . $subfix . rand(0, 9);
	}

	/**
	 * 因为有些渠道需要提交额外的参数，所以要对这些额外的参数进行验证
	 *
	 * @param string $channel
	 * @param array $rules
	 * @param array $messages
	 */
	protected function addExtraRulesBasedOnChannel($channel, &$rules, &$messages)
	{
		$extra = [];
		switch ($channel) {
			case 'alipay_wap':
				$rules['success_url'] = "required";
				$rules['cancel_url'] = "required";
				$messages['success_url.required'] = "请提交支付成功后的Client同步通知处理地址";
				$messages['cancel_url.required'] = "请提交支付取消后的Client同步通知处理地址";
				break;
			case 'bfb_wap':
				$rules['result_url'] = "required";
				$rules['bfb_login'] = "required";
				$messages['result_url.required'] = "请提交Client支付完成的同步回调地址";
				$messages['bfb_login.required'] = "请表明是否需要登录百度钱包来进行支付";
				break;
			case 'upacp_wap':
				$rules['result_url'] = "required";
				$messages['result_url.required'] = "请提交支付完成的同步回调地址";
				break;
			case 'wx_pub':
				$rules['open_id'] = "required";
				$messages['open_id.required'] = "请提交微信open_id";
				break;
			case 'wx_pub_qr':
				$rules['product_id'] = "required";
				$messages['product_id.required'] = "请提交产品id";
				break;
			case 'yeepay_wap':
				$rules['product_category'] = "required";
				$rules['identity_id'] = "required";
				$rules['identity_type'] = "required";
				$rules['terminal_type'] = "required";
				$rules['terminal_id'] = "required";
				$rules['user_ua'] = "required";
				$rules['result_url'] = "required";
				$messages['product_category.required'] = "请提交商品类别码";
				$messages['identity_id.required'] = "请提交用户标识";
				$messages['identity_type.required'] = "请提交用户标识类型";
				$messages['terminal_type.required'] = "请提交终端类型";
				$messages['terminal_id.required'] = "请提交终端ID";
				$messages['user_ua.required'] = "请提交用户使用的移动终端的UserAgent信息";
				$messages['result_url.required'] = "请提交前台通知地址";
				break;
			case 'jdpay_wap':
				$rules['success_url'] = "required";
				$rules['fail_url'] = "required";
				$rules['token'] = "required";
				$messages['success_url.required'] = "请提交支付成功页面跳转路径";
				$messages['fail_url.required'] = "请提交支付失败页面跳转路径";
				$messages['token.required'] = "请提交用户交易令牌";
				break;
		}

		return $extra;
	}

	/**
	 * 不同的设备设置了不同的APP_ID
	 *
	 * @param string $device
	 * @return string
	 */
	protected function getAppIdByDevice($device)
	{
		switch ($device) {
			case 'android':
				return self::APP_ID_ANDROID;
				break;
			case 'ios':
				return self::APP_ID_IOS;
				break;
			case 'wechat':
				return self::APP_ID_WECHAT;
				break;
			case 'pc':
				return self::APP_ID_PC;
				break;
		}
	}

	protected function getDeviceByAppId($appId)
	{
		if ($appId == self::APP_ID_ANDROID) {
			return 'android';
		}
		if ($appId == self::APP_ID_IOS) {
			return 'ios';
		}
		if ($appId == self::APP_ID_PC) {
			return 'pc';
		}
		if ($appId == self::APP_ID_WECHAT) {
			return 'wechat';
		}

		return null;
	}

	/**
	 * 根据不同的渠道返回不同的额外参数。
	 *
	 * @param string $channel
	 */
	protected function getExtraFromChannel($channel, $params)
	{
		
		$extra = [];
		switch ($channel) {
			case 'alipay_wap':
				$extra = [
					'success_url' => $params['success_url'],
					'cancel_url'  => $params['cancel_url'],
				];
				break;
			case 'alipay_pc_direct':
				$extra = [
					'success_url' => $params['success_url'],
				];
				break;
			case 'bfb_wap':
				$extra = [
					'result_url' => $params['result_url'],
					'bfb_login'  => $params['bfb_login'],
				];
				break;
			case 'upacp_wap':
				$extra = [
					'result_url' => $params['result_url'],
				];
				break;
			case 'wx_pub':
				$extra = [
					'open_id' => $params['open_id'],
				];
				break;
			case 'wx_pub_qr':
				$extra = [
					'product_id' => $params['product_id'],
				];
				break;
			case 'yeepay_wap':
				$extra = [
					'product_category' => $params['product_category'],
					'identity_id'      => $params['identity_id'],
					'identity_type'    => $params['identity_type'],
					'terminal_type'    => $params['terminal_type'],
					'terminal_id'      => $params['terminal_id'],
					'user_ua'          => $params['user_ua'],
					'result_url'       => $params['result_url'],
				];
				break;
			case 'jdpay_wap':
				$extra = [
					'success_url' => $params['success_url'],
					'fail_url'    => $params['fail_url'],
					'token'       => $params['token'],
				];
				break;
		}

		return $extra;
	}

	/**
	 * Important information from the post data that I might want to store into the database
	 *
	 * 统一支付的回调方法
	 *
	 * // TODO: make sure type = charge.succeeded
	 * // TODO: data.object.app = APP_ID
	 * // TODO: data.object.channel = wx_pub
	 * // TODO: data.object.order_no =
	 * // TODO: data.object.amount =
	 * // TODO: data.object.subject =
	 * // TODO: data.object.body =
	 * // TODO: data.object.transaction_no =
	 * // TODO: data.object.extra =
	 */
	public function chargeSucceeded()
	{
		$params = Input::all();
		Log::info(__METHOD__ . __LINE__ . " hitting" . json_encode($params));
		$rules = [
			'type' => [
				'required',
				'regex:/^(charge.succeeded)$/i',
			],
			'data' => 'required',
		];

		$messages = [
			'type.required' => '请提交类型',
			'type.regex'    => '请类型种类错误',
			'data.required' => '请提交数据',
		];

		$validator = Validator::make($params, $rules, $messages);
		if ($validator->fails()) {
			// the given data did not pass validation
			Log::error(sprintf("Validation errors on 'charge_succeeded' event: %s", json_encode($validator->errors())));

			return $this->makeView('errors.400', $validator->errors(), 400);
		}

		$data = $params['data'];
		$metadata = $params['data']['object']['metadata'];
		$channel = $params['data']['object']['channel'];

		$device = $this->getDeviceByAppId($data['object']['app']);
		if (!$device) {
			Log::error(__METHOD__ . __LINE__ . sprintf("找不到对应这个APP_ID: %s的设备。\n得到的请求数据是：%s.", $data['object']['app'], json_encode($params)));

			return $this->makeView('errors.503', 'APP_ID错误', 503);
		}

		// 钱包充值
		$event = null;
		if ($metadata['pay_type'] == 'wallet_recharge') {
			$order_no = $data['object']['order_no'];
			// 看看订单是否已经存在
			$transaction = WalletTransaction::getWalletTransaction($metadata['user_id'], WalletTransaction::TYPE_RECHARGE, $order_no, WalletTransaction::DIRECTION_IN);
			if (!$transaction) {
				$message = "微信充值";
				$attach_money = round($data['object']['amount'] / 100, 2);
				$wallet = Wallet::getWallet($metadata['user_id']);
				$wallet->recharge($metadata['user_id'], $attach_money, $message, $order_no, $channel);
			}
		} else {
			if ($metadata['pay_type'] == 'wallet_reward') {//打赏
				$order_no = $data['object']['order_no'];
				// 看看订单是否已经存在
				$transaction = WalletTransaction::getWalletTransaction($metadata['user_id'], WalletTransaction::TYPE_REWARD, $order_no, WalletTransaction::DIRECTION_IN);
				if (!$transaction) {
					$attach_money = round($data['object']['amount'] / 100, 2);
					$from_user = User::find($metadata['from_user_id']);
					$to_user = User::find($metadata['user_id']);
					$message = [];
					$message['send'] = sprintf("送心意给%s律师", $to_user->realname);
					$message['recive'] = sprintf("收到用户%s的心意", $from_user->realname);
					$wallet = Wallet::getWallet($metadata['user_id']);
					$wallet->reward($attach_money, $message, $order_no, $metadata['user_id'], $metadata['from_user_id'], $channel);
					$event = 'reward';
					$argument = [$from_user->id];
				}
			} else {
				if ($metadata['pay_type'] == 'order') {
					$attach_money = round($data['object']['amount'] / 100, 2);
					Log::info(__METHOD__ . __LINE__ . json_encode($metadata));
					$question_id = $metadata['question_id'];
					$question = Post::find($question_id);
					$order = $question->getOrder($question_id);
					$order_no = $data['object']['order_no'];
					try {
						$question->status = Post::STATUS_NEW;
						$question->save();
						if ($order) {
							Log::info("order info=".json_encode($data));														
							// ch_140aj9efjnDCbD8WX50S4WD0
							$order->pingpp_id 		= $data['object']['id'];
							$order->state 			= Order::STATE_PAID;
							$order->pay_status 		= Order::PAY_STATUS_PAIS;
							$order->pay_at 			= date('Y-m-d H:i:s');
							$order->associate_id 	= $order_no;
							$order->order_no 		= $data['object']['order_no'];
							$order->channel 		= $channel;
							$order->pay_price		= $attach_money;
							$order->save();		
						}									
						$lawyer = $question->getAssignedLawyer();
						if ($lawyer) {
							$message = sprintf("%s律师的%s", $lawyer->realname, $question->getType());
						} else {
							$message = $question->getType();
						}
						WalletTransaction::createOrder($this->getOrderType($question->type), $order_no, $question->creator_id, $attach_money, $message);
					} catch (Exception $ex) {
						Log::error($ex);
					}
					$event = 'pay_post';
					$argument = $question;
				}
			}
		}

		if ($event) {
			Event::fire($event, $argument);
		}
		return Response::json("success")->header('Content-Type', 'application/json')->setStatusCode(200);
	}

	protected function getOrderType($type)
	{
		$orderType = "";
		switch ($type) {
			case Post::TYPE_PAY_TEXT:
				$orderType = WalletTransaction::TYPE_PAY_TEXT;
				break;
			case Post::TYPE_PAY_PHONE:
				$orderType = WalletTransaction::TYPE_PAY_PHONE;
				break;
			case Post::TYPE_PAY_COMPANY:
				$orderType = WalletTransaction::TYPE_PAY_COMPANY;
				break;
		}

		return $orderType;
	}
	public function backUpacp1()
	{//银联支付前台通知、回调
		$params = Input::all();
		Log::info(__METHOD__ . __LINE__ . " 前台通知" . json_encode($params));
		if (isset ( $_POST ['signature'] )) {
			//echo com\unionpay\acp\sdk\AcpService::validate ( $_POST ) ? '验签成功' : '验签失败';
			$order_no = $_POST ['orderId']; //其他字段也可用类似方式获取
			$respCode = $_POST ['respCode']; //判断respCode=00或A6即可认为交易成功
			if($respCode=='00'||$respCode=='A6'){
				$attach_money = round($_POST['txnAmt'] / 100, 2);
				//Log::info(__METHOD__ . __LINE__ . json_encode());
				$question_id = $_POST['reqReserved'];//"question_id"
				$question = Post::find($question_id);
				$order = $question->getOrder($question_id);
				try {
					if($question->status == Post::STATUS_NEW){
						Log::info(__METHOD__ . __LINE__ .'-----前台重复支付'.$question_id);
						return Redirect::route('center.customer.wallet');
					}
					$question->status = Post::STATUS_NEW;
					$question->save();
					if ($order) {
						//Log::info("order info=".json_encode($order));
						$order->pingpp_id 		= '';
						$order->state 			= Order::STATE_PAID;
						$order->pay_status 		= Order::PAY_STATUS_PAIS;
						$order->pay_at 			= date('Y-m-d H:i:s');
						$order->associate_id 	= $question_id;
						$order->channel 		= '银联';
						$order->pay_price		= $attach_money;
						$order->save();		
					}									
					$lawyer = $question->getAssignedLawyer();
					if ($lawyer) {
						$message = sprintf("%s律师的%s", $lawyer->realname, $question->getType());
					} else {
						$message = $question->getType();
					}		
					WalletTransaction::createOrder($this->getOrderType($question->type), $order_no, $question->creator_id, $attach_money, $message);
				} catch (Exception $ex) {
					Log::error($ex);
					return $this->makeView('errors.400', $ex, 400);
				}
				$event = 'pay_post';
				$argument = $question;
				if ($event) {
					Event::fire($event, $argument);
				}
			}else{
				return $this->makeView('errors.400', '支付失败', 400);
			}
		} else {
			return $this->makeView('errors.400', '签名为空', 400);
		}
		
		Log::info("支付OK!");
		//Redirect::to('center/customer/wallet');
		return Redirect::route('center.customer.wallet');
	}
}
